梦幻曲:Android系统启动

之前花过一段时间整理了下Android系统启动、Activity启动以及ActivityThread等系统内容。时间久远,很多细节都忘了,本着互联共享的精神,在这里把之前的文档重新整理。计划写三篇文章:《梦幻曲:Android系统启动》,《沉思曲:Activity启动》、《小夜曲:ActivityThread分析》,一家之言难免有各种问题,仅供参考。
参考 | http://blog.csdn.net/jeffbao/article/details/18242515

概念


Dalvik虚拟机

当java程序运行时,都是有一个虚拟机来解释java的字节码,它将这些字节码翻译成本地CPU的指令码,然后执行。

AndroidRuntime

归纳起来的意思就是,Runtime 是支撑程序运行的基础库,它是与语言绑定在一起的。比如:

  • C Runtime:就是C standard lib,也就是我们常说的libc。(有意思的是, Wiki会自动将“C runtime" 重定向到 "C Standard Library")。
  • Java Runtime: 同样,Wiki将其重定向到” Java Virtual Machine",这里当然包括Java 的支撑类库(.jar)。
  • AndroidRuntime: 显而易见,就是为Android应用运行所需的运行时环境。包括:
    • Dalvik VM: Android的Java VM,解释运行Dex格式Java程序。每个进程运行一个虚拟机(什么叫运行虚拟机?说白了,就是一些C代码,不停的去解释Dex格式的二进制码(Bytecode),把它们转成机器码(Machine code),然后执行。
      • 当然,现在大多数的Java 虚拟机都支持JIT,也就是说,byte code可能在运行前就已经被转换成机器码,从而大大提高了性能。过去一个普遍的认识是Java 程序比C,C++等静态编译的语言慢,但随着JIT的介入和发展,这个已经完全是过去时了,JIT的动态性运行允许虚拟机根据运行时环境,优化机器码的生成,在某些情况下,Java甚至可以比C/C++跑得更快,同时又兼具平台无关的特性,这也是为什么Java如今如此流行的原因之一吧)。
    • Android的Java 类库, 大部分来自于 Apache Hamony, 开源的Java API 实现,如 java.lang, java.util, java.net. 但去除了AWT, Swing 等部件。
    • JNI: C和Java互调的接口。
    • Libc: Android也有很多C代码,自然少不了libc,注意的是,Android的libc叫 bionic C.


框架图

在往下讲之前,先看下框架图:

框架图.png

代码流程图

Android系统启动流程图.png

init进程


init进程的启动配置在init.rc文件中,
note:init.rc文件的语法可参考:init.rc分析

1.1、init进程启动ServiceManager

/*service后第一个参数为进程名,第二个参数为进程路径,后面参数为启动改进程传递的参数*/

//service关键字启动servicemanager
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm
  • Servicemanager负责管理所有的服务(native service、java service),如服务的注册、查找等。
  • native service主要有: surfaceflinger、drm、media等。
  • java service主要有:ActivityManagerService、WindowManagerService、PowerManagerService等。
  • 其中,native service大多在init.rc文件中由service关键字创建启动;java service大多由zygote创建启动。

1.2、init进程启动Zygote

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
  • 由service第二个参数可知,此处启动的进程为zygote进程,并由app_process实现。
  • zygote由java编写,不能有init进程直接启动;必须先生成Dalvik虚拟机,再在Dalvik虚拟机中装载zygote的实现类(ZygoteInit.java)。

Zygote进程


在往下讲Zygote进程前,先看附图,了解下Zygote都做啥了:

Zygote.png

Zygote进程的入口在app_main.cpp文件的main方法中,看下其main方法

2.1 main | app_main.cpp

int main(int argc, char* const argv[])
{
 ...
  //解析入参,此处入参为“--zygote --start-system-server”
  while (i < argc) {
      const char* arg = argv[i++];
      if (!parentDir) {
          parentDir = arg;
      } else if (strcmp(arg, "--zygote") == 0) {
          zygote = true;
          niceName = "zygote";
      } else if (strcmp(arg, "--start-system-server") == 0) {
          startSystemServer = true;
      } else if (strcmp(arg, "--application") == 0) {
          application = true;
      } else if (strncmp(arg, "--nice-name=", 12) == 0) {
          niceName = arg + 12;
      } else {
          className = arg;
          break;
      }
  }

  //设置进程名
  if (niceName && *niceName) {
      setArgv0(argv0, niceName);
      set_process_name(niceName);
  }

  runtime.mParentDir = parentDir;

  if (zygote) {
      //start生成并初始化Dalvik虚拟机,并加载ZygoteInit类到虚拟机中
      runtime.start("com.android.internal.os.ZygoteInit",
              startSystemServer ? "start-system-server" : "");
  } else if (className) {
      runtime.mClassName = className;
      runtime.mArgC = argc - i;
      runtime.mArgV = argv + i;
      //加载RuntimeInit类到虚拟机中
      runtime.start("com.android.internal.os.RuntimeInit",
              application ? "application" : "tool");
  } else {
      app_usage();
      return 10;
  }
}
  • 入参为“--zygote --start-system-server”,通过调用runtime.start创建和生成Dalvik虚拟机,并加载ZygoteInit类到虚拟机中。
  • 加载ZygoteInit类,调用其main方法,启动SystemServer。

2.2、main | ZygoteInit.java

public static void main(String argv[]) {
   try {
      //注册server socket
      //其它进程的创建,通过连接到该Socket后,由zygote孵化
      registerZygoteSocket();

      ...
      //预加载android framework类和资源
      preload();

      ...
      if (argv[1].equals("start-system-server")) {
          //启动SystemServer
          startSystemServer();
      } else if (!argv[1].equals("")) {
          throw new RuntimeException(argv[0] + USAGE_STRING);
      }

      //死循环接收client socket连接,由此创建新进程
      runSelectLoop();

      closeServerSocket();
  } catch (MethodAndArgsCaller caller) {
      caller.run();
  } catch (RuntimeException ex) {
      closeServerSocket();
      throw ex;
  }
}
  • 入参为"start-system-server",Zygote进程调用 startSystemServer()方法启动SystemServer。

2.3、startSystemServer

startSystemServer方法在ZygoteInit.java中,看方法名是要启动SystemServer进程了。

private static boolean startSystemServer()
        throws MethodAndArgsCaller, RuntimeException {
   ...
    //启动systemServer的参数
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "-- setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
        "--capabilities=" + capabilities + "," + capabilities,
        "--runtime-init",
        "--nice-name=system_server",
        //启动的SystemServer全限定名,后续根据该参数反射创建实例
        "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;
    try {
        /**
         * 将传入参数进行转换
         * 注意:参数com.android.server.SystemServer 放在parsedArgs中的remainingArgs里
         */
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        //Zygote为SystemServer创建子进程
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    //子进程执行
    if (pid == 0) {
        handleSystemServerProcess(parsedArgs);
    }
    return true;
}
  • Zygote为SystemServer创建新进程,并在新进程中调用handleSystemServerProcess。

SystemServer进程


上一步中调用了handleSystemServerProcess方法。

3.1、handleSystemServerProcess

该方法在ZygoteInit.java文件中

private static void handleSystemServerProcess(
        ZygoteConnection.Arguments parsedArgs)
        throws ZygoteInit.MethodAndArgsCaller {

    //关闭SystemServer进程的serversocket
    //SystemServer进程基础了父进程zygote所有资源
    closeServerSocket();

    //设置文件权限
    Libcore.os.umask(S_IRWXG | S_IRWXO);

    //设置新进程名
    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }

    if (parsedArgs.invokeWith != null) {
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                null, parsedArgs.remainingArgs);
    } else {
        //remainArgs中包含SystemServer的全限定名:com.android.server.SystemServer     
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
    }
}
  • 新进程中接着调用RuntimeInit.zygoteInit方法

3.2、RuntimeInit.zygoteInit

RuntimeInit.zygoteInit为静态方法,在RuntimeInit.java文件中。

public static final void zygoteInit(int targetSdkVersion, String[] argv)
        throws ZygoteInit.MethodAndArgsCaller {
    if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

    redirectLogStreams();

    commonInit();
    nativeZygoteInit();

    //调用该方法,往下执行
    applicationInit(targetSdkVersion, argv);
}

3.3、applicationInit

上方法接着调用了applicationInit方法,该方法在RuntimeInit.java文件中。

private static void applicationInit(int targetSdkVersion, String[] argv)
        throws ZygoteInit.MethodAndArgsCaller {
    //应用调用System.exit(),退出进程
    nativeSetExitWithoutCleanup(true);

    //设置堆
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args;
    try {
        args = new Arguments(argv);
    } catch (IllegalArgumentException ex) {
        Slog.e(TAG, ex.getMessage());
        return;
    }
  
    //创建args.startClass实例,并调用其main方法
    invokeStaticMain(args.startClass, args.startArgs);
}
  • 该方法接着调用invokeStaticMain方法,注意:此处args.startClass为com.android.server.SystemServer

3.4、invokeStaticMain

上方法接着调用了invokeStaticMain方法,该方同样在RuntimeInit.java中。看方法名,似乎是反射调用main方法。

private static void invokeStaticMain(String className, String[] argv)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    try {
        //全限定名,此处传入为"com.android.server.SystemServer"
        cl = Class.forName(className);
    }
    ...

    Method m;
    try {
        //main方法
        m = cl.getMethod("main", new Class[] { String[].class });
    }
    ...

    int modifiers = m.getModifiers();
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        throw new RuntimeException(
                "Main method is not public and static on " + className);
    }

    /**
     * 该异常会在ZygoteInit.main()中被捕获,
     * 捕获后会触发MethodAndArgsCaller的run()方法,
     * run方法中完成类main方法的调用
     */
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
  • 该方法最后通过抛异常的方式,抛出异常MethodAndArgsCaller;该异常被Zygote捕获,捕获后调用该异常的run方法,而在run放中完成类main方法的调用。
  • 因此,该步最后调用SystemServer的main方法。

3.5、main | SystemServer.java

终于调用SystemServer的main方法了,看下其java层代码主要干啥了。

public static void main(String[] args) {
    ...
    //SystemServer需要一直运行,因此它需要有效的利用内存
    VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

    Environment.setUserRequired(true);
    System.loadLibrary("android_servers");
   
    //初始化native服务
    nativeInit();

    //ServerThread并非Thread,它只是运行在SystemServer进程的主线程中
    ServerThread thr = new ServerThread();
    //调用该方法初始化和循环处理
    thr.initAndLoop();
}

3.6、initAndLoop

上面方法的主要内容在initAndLoop方法中,该方法是SystemServer的内部类ServerThread的方法。

public void initAndLoop() {
    ...
    //main looper
    Looper.prepareMainLooper();
    ...

    try {
        //启动DisplayManagerService服务,并注册到ServiceManager
        display = new DisplayManagerService(context, wmHandler);
        ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);

        //启动TelephonyRegistry服务,并注册到ServiceManager
        telephonyRegistry = new TelephonyRegistry(context);
        ServiceManager.addService("telephony.registry", telephonyRegistry);
      
        //启动其它服务,并注册到ServiceManager
        ...

        //启动ActivityManagerService
        ActivityManagerService.setSystemProcess();

        //启动其它服务,并注册到ServiceManager
        ...

    //调用ActivityManagerService的systemReady方法,启动Launcher
    ActivityManagerService.self().systemReady(new Runnable() {
        public void run() {
            ... 
            //开始系统启动画面
            if (!headless) {
                startSystemUi(contextF);
            }
           ...
    });

    //不停的从消息队列中获取消息
    Looper.loop();
}
  • initAndLoop方法中,SystemServer主要负责启动各种服务,并将启动的服务注册到ServiceManager中。
  • 上方法中注意ActivityManagerService的启动,可知:
    • AMS在SystemServier进程中运行;
    • SystemServer调用AMS的systemReady方法来启动系统UI了;

插话

上面讲完SystemServer进程创建后,下一部分就是应用进程创建了,这部分内容在后面文章展开,这里贴副图简单描述下Zygote是如何创建应用进程的。改图以Zygote创建Launcher进程为例:


zygote创建应用进程.png

总结


回顾整篇内容,可以用下图做个简单描述:

总结.png

本文从init进程启动出发,沿着zygote进程、SystemServer进程创建流程分析了Android系统启动,其中内容无非是这么几点:

  • init进程创建了Zygote进程
  • Zygote进程孵化创建了SystemServer进程
  • SystemServer进程启动了Android常见的系统服务,如AMS、PMS等。及SystemServer可理解为应用与之交互的远程服务端。
  • 已知Android的每个进程都与一个VM关联,上面代码未展开描述,但可概括为:VM由Zygote创建,Zygote每创建一个进程,就为为该进程拷贝一份VM实例,从而实现关联。

在后面的两篇文章中,会从Activity启动角度出发,分析Zygote是如何创建应用进程,以及ActivityThread有如何使主线程等问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容